#pragma once

#include "ObjectNode.h"

#include "Behavior.h"
#include "State.h"
#include "ValueSpecification.h"

namespace uml {

const bool ObjectNode::isControlType_default_ = false;
ObjectNode::ObjectNode(const QString& umlType)
    : ActivityNode(umlType) {}

void ObjectNode::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    ActivityNode::fromJson(json, errorList);
    TypedElement::fromJson(json, errorList);
    JsonSerializable::fromJsonArray(inStates_, "inStates", json, errorList);
    isControlType_ = json.value("isControlType").toBool(isControlType_default_);
    ordering_ = (ObjectNodeOrderingKind)json.value("ordering").toInt((int)ordering_);
    selection_ = JsonSerializable::create<Behavior>(json.value("selection"), errorList);

    upperBound_ = JsonSerializable::create<ValueSpecification>(json.value("upperBound"), errorList);

}

void ObjectNode::toJson(QJsonObject& json) {
    ActivityNode::toJson(json);
    TypedElement::toJson(json);
    JsonSerializable::toJsonArray(inStates_, "inStates", json);
    if (isControlType_ != isControlType_default_) {
        json.insert("isControlType", isControlType_);
    }
    json.insert("ordering", (int)ordering_);
    if (selection_) {
        QJsonObject selection_json;
        selection_->toJson(selection_json);
        json.insert("selection", selection_json);
    }
    if (upperBound_) {
        QJsonObject upperBound_json;
        upperBound_->toJson(upperBound_json);
        json.insert("upperBound", upperBound_json);
    }
}

/// <summary>
/// inStates getter
/// The States required to be associated with the values held by tokens on this
/// ObjectNode.
/// </summary>
vector<shared_ptr<State>>& ObjectNode::inStates() {
    return inStates_;
}

/// <summary>
/// isControlType getter
/// Indicates whether the type of the ObjectNode is to be treated as representing
/// control values that may traverse ControlFlows.
/// </summary>
bool ObjectNode::isControlType() const {
    return isControlType_;
}

/// <summary>
/// isControlType setter
/// Indicates whether the type of the ObjectNode is to be treated as representing
/// control values that may traverse ControlFlows.
/// </summary>
void ObjectNode::setIsControlType(bool value) {
    isControlType_ = value;
}

/// <summary>
/// ordering getter
/// Indicates how the tokens held by the ObjectNode are ordered for selection to
/// traverse ActivityEdges outgoing from the ObjectNode.
/// </summary>
ObjectNodeOrderingKind ObjectNode::ordering() const {
    return ordering_;
}

/// <summary>
/// ordering setter
/// Indicates how the tokens held by the ObjectNode are ordered for selection to
/// traverse ActivityEdges outgoing from the ObjectNode.
/// </summary>
void ObjectNode::setOrdering(ObjectNodeOrderingKind value) {
    ordering_ = value;
}

/// <summary>
/// selection getter
/// A Behavior used to select tokens to be offered on outgoing ActivityEdges.
/// </summary>
shared_ptr<Behavior> ObjectNode::selection() const {
    return selection_;
}

/// <summary>
/// selection setter
/// A Behavior used to select tokens to be offered on outgoing ActivityEdges.
/// </summary>
void ObjectNode::setSelection(shared_ptr<Behavior> value) {
    selection_ = value;
}

/// <summary>
/// upperBound getter
/// The maximum number of tokens that may be held by this ObjectNode. Tokens cannot
/// flow into the ObjectNode if the upperBound is reached. If no upperBound is
/// specified, then there is no limit on how many tokens the ObjectNode can hold.
/// </summary>
shared_ptr<ValueSpecification> ObjectNode::upperBound() const {
    return upperBound_;
}

/// <summary>
/// upperBound setter
/// The maximum number of tokens that may be held by this ObjectNode. Tokens cannot
/// flow into the ObjectNode if the upperBound is reached. If no upperBound is
/// specified, then there is no limit on how many tokens the ObjectNode can hold.
/// </summary>
void ObjectNode::setUpperBound(shared_ptr<ValueSpecification> value) {
    upperBound_ = value;
}

} // namespace uml
